package cas;

import gov.nasa.worldwind.geom.LatLon;
import gov.nasa.worldwind.geom.Position;

import java.sql.SQLException;
import java.util.Date;
import java.util.List;

import util.Converter;
import util.LengthMeasurer;
import util.NumberUtil;
import util.RuteUtil;

import bean.KeretaApiBean;
import bean.KoordinatBean;
import bean.RuteBean;
import dao.DAOFactory;
import dao.oracle.KeretaApiDao;
import dao.oracle.RuteDao;

/**
 * @author Eri Setiawan
 * @version 1.0
 * @created 29-May-2011 10:32:52 AM
 */
public class Identity {
	private LatLon curCoord;
	private List<RuteBean> rute;
	private KeretaApiBean keretaApi;
	private int gerbongIsi;
	private int gerbongKosong;
	private double panjangRangkaian;
	private double timeDiff;
	private int urutan;
	private double speed;
	private double acceleration;
	public final static double PANJANG_LOKO = 14.135;
	public final static double PANJANG_GERBONG = 20.920;

	public Identity(){
		super();
		timeDiff = 0;
	}
	
	public Identity(LatLon curCoord, List<RuteBean> rute,
			KeretaApiBean keretaApi, int gerbongIsi, int gerbongKosong,
			double panjangRangkaian, double timeDiff, int urutan,
			double speed, double acceleration) {
		super();
		this.curCoord = curCoord;
		this.rute = rute;
		this.keretaApi = keretaApi;
		this.gerbongIsi = gerbongIsi;
		this.gerbongKosong = gerbongKosong;
		this.panjangRangkaian = panjangRangkaian;
		this.timeDiff = timeDiff;
		this.urutan = urutan;
		this.speed = speed;
		this.acceleration = acceleration;
	}

	public Identity(String data) throws SQLException {
		String[] splitted = data.split(",");
		KeretaApiDao lokoDao = DAOFactory.createKeretaApiDao();
		RuteDao ruteDao = DAOFactory.createRuteDao();
		try {
			keretaApi = lokoDao.getKeretaApiWhereNoKeretaAndIdJenis(Integer.valueOf(splitted[1]), splitted[0].substring(1));
			gerbongIsi = Integer.valueOf(splitted[2]);
			gerbongKosong = Integer.valueOf(splitted[3]);
			setCurCoord(LatLon.fromDegrees(Double.valueOf(splitted[4]), Double.valueOf(splitted[5])));
			rute = ruteDao.getRuteWhereNamaRute(splitted[6]);
			urutan = Integer.valueOf(splitted[7]);
			timeDiff = Double.valueOf(splitted[8].split("\n")[0]);
		} catch (NumberFormatException e) {
			e.printStackTrace();
		}
	}
	/*
	 * Panjang rangkaian dalam satuan meter
	 */
	public double getPanjangRangkaian(){
		return panjangRangkaian;
	}
	public LatLon getCurCoord() {
		return curCoord;
	}
	public void setCurCoord(LatLon newCoord) {
		if(timeDiff!=0){			
			//Hitung kecepatan.
			Vektor vektor = new Vektor(curCoord, newCoord, timeDiff);
			double newSpeed =  vektor.getLength();
			
			//hitung percepatan
			setAcceleration((newSpeed -speed)/timeDiff);
			speed = newSpeed;	
		}
		curCoord = newCoord;
	}
	public int getJumlahGerbong() {
		return gerbongIsi + gerbongKosong;
	}
	public void setGerbong(int gerbongIsi, int gerbongKosong) {
		setGerbongIsi(gerbongIsi);
		setGerbongKosong(gerbongKosong);
		panjangRangkaian = PANJANG_LOKO +getJumlahGerbong()*PANJANG_GERBONG;
	}
	public List<RuteBean> getRute() {
		return rute;
	}
	public KoordinatBean getCurRuteCoord(){
		return getRute().get(getUrutan()).getKoordinat();
	}
	public void setRute(List<RuteBean> rute) {
		this.rute = rute;
	}
	public KeretaApiBean getKeretaApi() {
		return keretaApi;
	}
	public void setKeretaApi(KeretaApiBean keretaApi) {
		this.keretaApi = keretaApi;
	}
	public int getUrutan() {
		return urutan;
	}
	public void setUrutan(int urutan) {
		this.urutan = urutan;
	}
	
	public int getGerbongIsi() {
		return gerbongIsi;
	}
	private void setGerbongIsi(int gerbongIsi) {
		this.gerbongIsi = gerbongIsi;
	}
	public int getGerbongKosong() {
		return gerbongKosong;
	}
	private void setGerbongKosong(int gerbongKosong) {
		this.gerbongKosong = gerbongKosong;
	}
	/**
	 * In Kilometer
	 * @return
	 */
	public double getMaxSpeed(){
		return getKeretaApi().getJenisKeretaApi().getMaxSpeed();
	}
	/**
	 * In Kilometer
	 * @return
	 */
	public double getAllowedMaxSpeed(){
		return getRute().get(getUrutan()).getMaxSpeedAllowed();
	}
	@Override
	public String toString() {
		String result = "";
		result = "$"+keretaApi.getJenisKeretaApi().getIdJenisKa()+","+
		keretaApi.getNoKeretaApi()+","+
		gerbongIsi+","+
		gerbongKosong+","+
		curCoord.getLatitude().getDegrees()+","+
		curCoord.getLongitude().getDegrees()+","+
		rute.get(0).getNamaRute()+ ","+
		urutan+ ","+
		timeDiff+"\n";
		return result;
	}
	/**
	 * In Coordinate
	 * @param speed
	 */
	public void setSpeed(double speed) {
		this.speed = speed;
	}
	public double getSpeed(boolean isInMeter) {
		if(isInMeter)
			return Converter.degreesToMeter(speed, curCoord);
		else
			return speed;
	}
	public Position getPosition(){
		return Position.fromDegrees(curCoord.getLatitude().getDegrees(), curCoord.getLongitude().getDegrees());
	}
	private void setAcceleration(double acceleration) {
		this.acceleration = acceleration;
	}
	public double getAcceleration() {
		return acceleration;
	}
	public boolean isAtFront(Identity anotherTrain, Integer[] sameId) {
		double myDistance = LengthMeasurer.distanceBetween(this, sameId[0]);
		double anotherTrainDistance = LengthMeasurer.distanceBetween(anotherTrain, sameId[0]);
		if(myDistance<anotherTrainDistance){
			return true;
		}
		return false;
	}
	public boolean isInSameDirection(Identity anotherTrain, Integer[] sameId) {
		int[] urutan1 = new int[sameId.length];
		int[] urutan2 = new int[sameId.length];
		for (int i = 0; i < sameId.length; i++) {
			urutan1[i] = RuteUtil.getUrutanWhereCoordId(getRute(), sameId[i]);
			urutan2[i] = RuteUtil.getUrutanWhereCoordId(anotherTrain.getRute(), sameId[i]);
		}
		if(NumberUtil.isAscending(urutan1)&&NumberUtil.isAscending(urutan2)){
			return true;
		}else if(NumberUtil.isDescending(urutan1)&&NumberUtil.isDescending(urutan2)){
			return true;
		}
		return false;
	}
	public boolean isInSameFlatform(Integer[] allSameCoordId) {
		Integer[] urutan = getlistUrutan(allSameCoordId);
			if(!NumberUtil.isContains(urutan, getUrutan()))
				return false;
			if(!NumberUtil.isContains(urutan, getUrutan()+1))
				return false;	
		return true;
	}
	public Integer[] getlistUrutan(Integer[] listCoordId){
		Integer[] urutan = new Integer[listCoordId.length];
		for (int i = 0; i < listCoordId.length; i++) {
			urutan[i] = RuteUtil.getUrutanWhereCoordId(getRute(), listCoordId[i]);
		}
		return urutan;
	}
	public Identity copy(){
		return new Identity(
				LatLon.fromDegrees(curCoord.getLatitude().getDegrees(), curCoord.getLongitude().getDegrees()), 
				rute, 
				keretaApi, 
				gerbongIsi, 
				gerbongKosong, 
				panjangRangkaian, 
				timeDiff, urutan, speed, acceleration);
	}
	public void setTimeDiff(double timeDiff){
		this.timeDiff = timeDiff;
	}
}